package net.chrisrichardson.ec2deployer.cluster

import groovy.mock.interceptor.MockFor
import net.chrisrichardson.ec2deployer.core.EC2
import net.chrisrichardson.ec2deployer.core.AWSProperties
import net.chrisrichardson.ec2deployer.core.EC2Server
import net.chrisrichardson.ec2deployer.applications.MySqlServer

class DatabaseTierTest extends GroovyTestCase {

    def mockEc2
    AWSProperties awsProperties
    ClusterSpec clusterSpec
    MockFor mockMySqlServer
    def masterInstance
    def slaveInstance
    MockFor mockEC2Server

    DatabaseTier databaseTier

    public void setUp() {
        mockEc2 = new MockFor(EC2.class)
        mockMySqlServer = new MockFor(MySqlServer.class)
        mockEC2Server = new MockFor(EC2Server.class)

        def props = new Properties()
        awsProperties = new AWSProperties(props)

        clusterSpec = new ClusterSpec().tomcats(1).slaves(1).webApp('target/ptrack', "ptrack").catalinaOptsBuilder({builder, databasePrivateDnsName ->}).schema("ptrack", ["ptrack": "ptrack"])

    }

    public void testAssignHosts() {
        def ec2 = new EC2(awsProperties)
        databaseTier = new DatabaseTier(ec2, clusterSpec)
        slaveInstance = new EC2Server()
        masterInstance = new EC2Server()
        def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
        databaseTier.assignHosts(hosts)
        assertEquals masterInstance, databaseTier.databaseServer.host
        assertEquals 1, databaseTier.mySqlSlaves.size
        assertEquals slaveInstance, databaseTier.mySqlSlaves[0].host
    }

    public void testStart() {
        def ec2 = new EC2(awsProperties)
        databaseTier = new DatabaseTier(ec2, clusterSpec)

        mockMySqlServer.demand.configureAsMaster {}
        mockMySqlServer.demand.configureAsSlave {}
        mockMySqlServer.demand.dbCreateOnStartup{}

        mockMySqlServer.use {
            slaveInstance = new EC2Server()
            masterInstance = new EC2Server()
            def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
            databaseTier.assignHosts(hosts)
            databaseTier.start()
        }
    }

    public void testStartWithExistingEbsVolume() {
        clusterSpec.withExistingEbsVolume("vol-123434", "/dev/sdq")

        def ec2 = new EC2(awsProperties)
        databaseTier = new DatabaseTier(ec2, clusterSpec)

        mockMySqlServer.demand.configureAsMaster {}
        mockMySqlServer.demand.configureAsSlave {}

        mockMySqlServer.use {
            slaveInstance = new EC2Server()
            masterInstance = new EC2Server()
            def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
            databaseTier.assignHosts(hosts)
            databaseTier.start()
        }
    }

    public void testStartWithNewEbsVolume() {
        clusterSpec.withNewEbsVolume(10, "/dev/sdq")

        def ec2 = new EC2(awsProperties)
        databaseTier = new DatabaseTier(ec2, clusterSpec)

        mockMySqlServer.demand.configureAsMaster {
            clusterSpec.ebsVolume.volumeId = "vol-223"
        }
        mockMySqlServer.demand.configureAsSlave {
        }
        mockMySqlServer.demand.dbCreateOnStartup{}

        mockMySqlServer.use {
            slaveInstance = new EC2Server()
            masterInstance = new EC2Server()
            def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
            databaseTier.assignHosts(hosts)
            databaseTier.start()
        }
    }

    public void testSaveState() {
        def ec2 = new EC2(awsProperties)
        databaseTier = new DatabaseTier(ec2, clusterSpec)

        mockMySqlServer.demand.getHost {masterInstance}
        mockMySqlServer.demand.getHost {slaveInstance}

        mockEC2Server.demand.getInstanceId() {"i-slave"}
        mockEC2Server.demand.getInstanceId() {"i-master"}

        mockEC2Server.use {
            mockMySqlServer.use {
                slaveInstance = new EC2Server()
                masterInstance = new EC2Server()
                def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
                databaseTier.assignHosts(hosts)
                def state = [:]
                databaseTier.saveState(state)

                assertEquals(["i-slave"], state["mySqlSlaves"])
                assertEquals(["i-master"], state["databaseServer"])
            }
        }
    }

    public void testRestoreState() {
        def state = [databaseServer: ["i-master"], mySqlSlaves: ["i-slave"]]
        slaveInstance = new EC2Server()
        masterInstance = new EC2Server()

        def instancesById = ["i-master": masterInstance, "i-slave": slaveInstance]

        2.times {mockEc2.demand.findInstance {id -> instancesById[id]}}

        mockEc2.use {
            def ec2 = new EC2(awsProperties)
            databaseTier = new DatabaseTier(ec2, clusterSpec)
            databaseTier.restoreState(state)

            assertEquals masterInstance, databaseTier.databaseServer.host
            assertEquals 1, databaseTier.mySqlSlaves.size
            assertEquals slaveInstance, databaseTier.mySqlSlaves[0].host
        }
    }

    public void testConfigureMasterBackup() {
        mockMySqlServer.demand.configureBackup {String bucket, String objectPrefix, boolean master ->
            assertEquals "myBucket", bucket
            assertEquals "myObjectPrefix", objectPrefix
            assert master
        }
        mockMySqlServer.use {
            def ec2 = new EC2(awsProperties)
            databaseTier = new DatabaseTier(ec2, clusterSpec)
            slaveInstance = new EC2Server()
            masterInstance = new EC2Server()
            def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
            databaseTier.assignHosts(hosts)

            databaseTier.configureMasterBackup "myBucket", "myObjectPrefix"
        }
    }

    public void testConfigureSlaveBackup() {

        mockMySqlServer.demand.getHost {
            slaveInstance
        }

        mockEC2Server.demand.getInstanceId {
          "i-334"
        }
        
        mockMySqlServer.demand.configureBackup {String bucket, String objectPrefix, boolean master ->
            assertEquals "myBucket", bucket
            assertEquals "myObjectPrefix", objectPrefix
            assert !master
        }

        mockEC2Server.use {
            mockMySqlServer.use {
                def ec2 = new EC2(awsProperties)
                databaseTier = new DatabaseTier(ec2, clusterSpec)
                slaveInstance = new EC2Server()
                masterInstance = new EC2Server()
                def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
                databaseTier.assignHosts(hosts)

                databaseTier.configureSlaveBackup "i-334", "myBucket", "myObjectPrefix"
            }
        }
    }

    public void testStopSlave() {
        mockEC2Server.demand.stop {}

        mockEC2Server.use {
            def ec2 = new EC2(awsProperties)
            databaseTier = new DatabaseTier(ec2, clusterSpec)
            slaveInstance = new EC2Server()
            masterInstance = new EC2Server()
            def hosts = new ClusterHosts(mySqlSlaves: [slaveInstance], databaseServer: masterInstance)
            databaseTier.assignHosts(hosts)
            databaseTier.stopSlave()
            assertEquals masterInstance, databaseTier.databaseServer.host
            assertEquals 0, databaseTier.mySqlSlaves.size
        }
    }


}